/*
 * Copyright 2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cc.siyecao.mapper.service;

import cc.siyecao.mapper.CloverMapper;
import cc.siyecao.mapper.common.core.Code;
import cc.siyecao.mapper.common.util.Assert;
import cc.siyecao.mapper.function.Fn;
import cc.siyecao.mapper.provider.entity.EntityColumn;
import cc.siyecao.mapper.provider.entity.EntityTable;
import cc.siyecao.mapper.wrapper.LambdaWrapper;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * 基础方法实现，推荐自己的实现类继承该类
 * <p>
 * 例如自己的接口：
 * <pre>
 *   public interface UserService {
 *     User save(User user);
 *   }
 * </pre>
 * 对应的实现类:
 * <pre>
 *   public class UserServiceImpl extends AbstractService&lt;User, Long, UserMapper&gt; implements UserService {
 *       //由于 User save(User user); 和默认的 T save(T entity) 方法一致，所以不需要提供实现，可以用默认方法
 *   }
 * </pre>
 *
 * @param <T>  实体类类型
 * @param <ID> 主键类型
 * @param <M>  Mapper类型
 * @author liuzh
 */
public class BaseServiceImpl<T, ID extends Serializable, M extends CloverMapper<T, ID>>
        implements BaseService<T, ID> {

    protected M mapper;

    @Autowired
    public void setMapper(M mapper) {
        this.mapper = mapper;
    }

    @Override
    public T save(T entity) {
        Assert.isTrue( mapper.insert( entity ) == 1, Code.SAVE_FAILURE );
        return entity;
    }

    @Override
    public T saveSelective(T entity) {
        Assert.isTrue( mapper.insertSelective( entity ) == 1, Code.SAVE_FAILURE );
        return entity;
    }

    @Override
    public T update(T entity) {
        Assert.isTrue( mapper.updateById( entity ) == 1, Code.UPDATE_FAILURE );
        return entity;
    }

    @Override
    public T updateSelective(T entity) {
        Assert.isTrue( mapper.updateByIdSelective( entity ) == 1, Code.UPDATE_FAILURE );
        return entity;
    }

    @Override
    public boolean pkHasValue(T entity) {
        EntityTable entityTable = mapper.entityTable();
        List<EntityColumn> idColumns = entityTable.idColumns();
        return idColumns.get( 0 ).field().get( entity ) != null;
    }

    @Override
    public T saveOrUpdate(T entity) {
        if (pkHasValue( entity )) {
            return update( entity );
        } else {
            return save( entity );
        }
    }

    @Override
    public T saveOrUpdateSelective(T entity) {
        if (pkHasValue( entity )) {
            return updateSelective( entity );
        } else {
            return saveSelective( entity );
        }
    }

    @Override
    public int remove(T entity) {
        return mapper.delete( entity );
    }

    @Override
    public int removeById(ID id) {
        int count = mapper.deleteById( id );
        Assert.isTrue( count == 1, Code.DELETE_FAILURE );
        return count;
    }

    @Override
    public <F> int removeByFieldList(Fn<T, F> field, List<F> fieldValueList) {
        return mapper.deleteByFieldList( field, fieldValueList );
    }

    /**
     * 根据指定的主键查询
     *
     * @param id 主键
     * @return 实体
     */
    @Override
    public T findById(ID id) {
        return mapper.selectById( id ).orElse( null );
    }

    /**
     * 以当前类作为条件查询一个，当结果多于1个时出错
     *
     * @param entity 实体类
     * @return 实体
     */
    @Override
    public T findOne(T entity) {
        return mapper.selectOne( entity ).orElse( null );
    }

    /**
     * 以当前类作为条件查询
     *
     * @param entity 实体类
     * @return 实体集合
     */
    @Override
    public List<T> findList(T entity) {
        return mapper.selectList( entity );
    }

    /**
     * 根据指定字段集合查询
     *
     * @param field          字段
     * @param fieldValueList 字段值集合
     * @param <F>            字段值类型
     * @return 实体集合
     */
    @Override
    public <F> List<T> findByFieldList(Fn<T, F> field, List<F> fieldValueList) {
        return mapper.selectByFieldList( field, fieldValueList );
    }

    /**
     * 查询全部
     *
     * @return 实体集合
     */
    @Override
    public List<T> findAll() {
        return mapper.selectList( null );
    }

    /**
     * 以当前类作为条件查询总数
     *
     * @param entity 实体类
     * @return 实体集合
     */
    @Override
    public long count(T entity) {
        return mapper.count( entity );
    }

    /**
     * 根据 wrapper 条件批量删除
     *
     * @param wrapper 查询条件
     * @return 返回大于0成功，0失败
     */
    @Override
    public int remove(LambdaWrapper<T> wrapper) {
        return mapper.deleteByWrapper( wrapper );
    }

    /**
     * 根据 wrapper 查询条件批量更新（所有字段）
     *
     * @param entity  实体类
     * @param wrapper 查询条件
     * @return 返回大于0成功，0失败
     */
    @Override
    public int update(T entity, LambdaWrapper<T> wrapper) {
        return mapper.updateByWrapper( entity, wrapper );
    }

    /**
     * 根据 wrapper 查询条件批量更新（非空字段）
     *
     * @param entity  实体类
     * @param wrapper 查询条件
     * @return 返回大于0成功，0失败
     */
    @Override
    public int updateSelective(T entity, LambdaWrapper<T> wrapper) {
        return mapper.updateByWrapperSelective( entity, wrapper );
    }

    /**
     * 根据 wrapper 查询条件批量更新（所有字段）
     *
     * @param wrapper 查询条件
     * @return 返回大于0成功，0失败
     */
    @Override
    public int update(LambdaWrapper<T> wrapper) {
        return mapper.updateByWrapper( null, wrapper );
    }

    /**
     * 根据 wrapper 查询条件批量更新（所有字段）
     *
     * @param wrapper 查询条件
     * @return 返回大于0成功，0失败
     */
    @Override
    public int updateSelective(LambdaWrapper<T> wrapper) {
        return mapper.updateByWrapperSelective( null, wrapper );
    }

    /**
     * 根据 wrapper 条件查询一个，当结果多于1个时出错
     *
     * @param wrapper 查询条件
     * @return 实体
     */
    @Override
    public T findOne(LambdaWrapper<T> wrapper) {
        return mapper.selectOneByWrapper( wrapper ).orElse( null );
    }

    /**
     * 根据 wrapper 条件查询
     *
     * @param wrapper 查询条件
     * @return 实体
     */
    @Override
    public <N> N findByWrapper(LambdaWrapper<T> wrapper) {
        return mapper.findByWrapper(wrapper);
    }

    /**
     * 根据 wrapper 条件查询
     *
     * @param wrapper 查询条件
     * @return 实体集合
     */
    @Override
    public List<T> findList(LambdaWrapper<T> wrapper) {
        return mapper.selectByWrapper( wrapper );
    }

    /**
     * 根据 wrapper 查询总数
     *
     * @param wrapper 查询条件
     * @return 总数
     */
    @Override
    public long count(LambdaWrapper<T> wrapper) {
        return mapper.countByWrapper( wrapper );
    }

    /**
     * 批量保存实体，需要数据库支持批量插入的语法
     *
     * @param entityList 实体列表
     * @return 结果数等于 entityList.size() 时成功，不相等时失败
     */
    @Override
    public int saveBatch(List<T> entityList) {
        return mapper.insertBatch( entityList );
    }

    /**
     * 批量更新实体，需要数据库支持批量插入的语法
     *
     * @param entityList 实体列表
     * @return 结果数等于 entityList.size() 时成功，不相等时失败
     */
    @Override
    public int updateBatch(List<T> entityList) {
        return mapper.updateBatch( entityList );
    }

    /**
     * 批量更新实体非空字段，需要数据库支持批量插入的语法
     *
     * @param entityList 实体列表
     * @return 结果数等于 entityList.size() 时成功，不相等时失败
     */
    @Override
    public int updateBatchSelective(List<T> entityList) {
        return mapper.updateBatchSelective( entityList );
    }

    /**
     * 根据ID批量删除实体，需要数据库支持批量插入的语法
     *
     * @param idList 实体列表
     * @return 结果数等于 idList.size() 时成功，不相等时失败
     */
    @Override
    public int removeBatchIds(Collection<ID> idList) {
        return mapper.deleteBatchIds( idList );
    }

    /**
     * 根据ID批量删除实体，需要数据库支持批量插入的语法
     *
     * @param ids 实体列表
     * @return 结果数等于 ids.length 时成功，不相等时失败
     */
    @Override
    public int removeBatchIds(ID... ids) {
        return mapper.deleteBatchIds( Arrays.asList( ids ) );
    }

    /**
     * 根据ID批量查询实体，需要数据库支持批量插入的语法
     *
     * @param idList 实体Id列表
     * @return
     */
    @Override
    public List<T> findByIds(Collection<ID> idList) {
        return mapper.selectByIds( idList );
    }

    /**
     * 根据ID批量查询实体，需要数据库支持批量插入的语法
     *
     * @param ids 实体Id列表
     * @return
     */
    @Override
    public List<T> findByIds(ID... ids) {
        return mapper.selectByIds( Arrays.asList( ids ) );
    }
}
